﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml.Linq;
using tiDE.API;
using System.Runtime.Serialization.Formatters.Binary;
using tiDE.Runtime;
using tiDE.Packers;

namespace tiDE
{
    public partial class CreateProjectDialog : Form
    {


        public CreateProjectDialog()
        {
            InitializeComponent();
            ProjectsDirectory = RuntimeData.tiDEUserDirectory + "\\Projects";
            textBox2.Text = RuntimeData.tiDEUserDirectory + "\\Projects";
            DialogResult = System.Windows.Forms.DialogResult.Cancel;
        }

        string ProjectsDirectory;
        bool hasNameChanged = false, isChangeHandled = false;

        private void CreateProjectDialog_Load(object sender, EventArgs e)
        {
            // Load all the templates
            string[] templateDefs;
            try
            {
                templateDefs = Directory.GetFiles(Directory.GetCurrentDirectory() + "\\Templates", "*.tidet");
                List<string> defs = new List<string>(templateDefs);
                defs.AddRange(Directory.GetFiles(RuntimeData.tiDEUserDirectory + "\\Templates", "*.tidet"));
                templateDefs = defs.ToArray();
            }
            catch
            {
                MessageBox.Show("Unable to load templates");
                return;
            }
            StreamReader reader;
            foreach (string template in templateDefs)
            {
                reader = new StreamReader(template);
                XDocument templateXml = XDocument.Parse(reader.ReadToEnd());
                XElement templateElement = templateXml.Element("ProjectTemplate");
                string templateName = "", templateIcon = "",
                    templateCat = "Default Category";
                if (templateElement.Attribute("Name") != null)
                    templateName = templateElement.Attribute("Name").Value;
                else
                    continue;
                if (templateElement.Attribute("Icon") != null)
                    templateIcon = templateElement.Attribute("Icon").Value;
                if (templateElement.Attribute("Category") != null)
                    templateCat = templateElement.Attribute("Category").Value;
                if (File.Exists("Templates\\" + templateIcon))
                    imageList1.Images.Add(Image.FromFile("Templates\\" + templateIcon));
                else
                    imageList1.Images.Add(Image.FromFile("Templates\\default.ico"));
                ListViewItem item = new ListViewItem(templateName, imageList1.Images.Count - 1);
                item.Tag = templateElement;
                bool groupFound = false;
                foreach (ListViewGroup group in listView1.Groups)
                {
                    if (group.Header == templateCat)
                    {
                        item.Group = group;
                        groupFound = true;
                        break;
                    }
                }
                if (!groupFound)
                {
                    ListViewGroup group = new ListViewGroup(templateCat);
                    item.Group = group;
                    listView1.Groups.Add(group);
                }
                listView1.Items.Add(item);
            }
            isChangeHandled = true;
            listView1.Items[0].Selected = true;
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            button1.Enabled = Directory.Exists(textBox2.Text);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count == 0)
            {
                // If no type of project is selected
                button1.Enabled = false;
                return;
            }
            else
                // If any kind of project is selected
                button1.Enabled = true;

            XElement element = (XElement)listView1.SelectedItems[0].Tag;
            if (element.Attribute("Description") != null)
                label4.Text = element.Attribute("Description").Value;
            else
                label4.Text = "";

            if (!hasNameChanged)
            {
                isChangeHandled = true;
                string projectName = listView1.SelectedItems[0].Text.Replace(" ", "");
                int projectNameOffset = 1;
                while (Directory.Exists(textBox2.Text + "\\" + projectName + projectNameOffset.ToString()))
                {
                    projectNameOffset++;
                }
                textBox1.Text = projectName + projectNameOffset.ToString();
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            if (isChangeHandled)
            {
                isChangeHandled = false;
                return;
            }
            hasNameChanged = true;
            if (textBox1.Text == "")
                button1.Enabled = false;
            else
                button1.Enabled = true;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
            textBox2.Text = folderBrowserDialog1.SelectedPath;
        }

        public Solution Solution;

        private void button1_Click(object sender, EventArgs e)
        {
            XElement templateElement = listView1.SelectedItems[0].Tag as XElement;

            string ProjectName = textBox1.Text;
            List<string> Files;
            List<string> SupportedModels;
            List<string> Dependencies;
            List<string> OpenFiles = new List<string>();
            string FocusedFile = "";
            string ProjectType;
            string EmulatingModel = "";
            string Packer = "";

            string ProjectDirectory = textBox2.Text + "\\" + ProjectName;
            if (Directory.Exists(ProjectDirectory))
            {
                MessageBox.Show("Project already exists.\nPlease select another location.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            Directory.CreateDirectory(ProjectDirectory);
            Directory.CreateDirectory(ProjectDirectory + "\\" + ProjectName);

            if (templateElement.Attribute("Type") != null)
            {
                ProjectType = templateElement.Attribute("Type").Value;
            }
            else
            {
                MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK,MessageBoxIcon.Error);
                return;
            }

            if (templateElement.Attribute("Packer") != null)
            {
                Packer = templateElement.Attribute("Packer").Value;
            }
            else
            {
                MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            Type projectDataType = null;
            if (templateElement.Attribute("ProjectWizard") != null)
            {
                projectDataType = Type.GetType(templateElement.Attribute("ProjectWizard").Value);
            }

            Solution = new Solution(ProjectName);

            if (templateElement.Attribute("Language") != null)
            {
                Solution.Language = templateElement.Attribute("Language").Value;
            }

            if (templateElement.Element("Files") != null)
            {
                Files = new List<string>();
                foreach (XElement file in templateElement.Element("Files").Elements("File"))
                {
                    string FileName;
                    if (file.Attribute("Name") != null)
                        FileName = file.Attribute("Name").Value;
                    else
                    {
                        MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK,MessageBoxIcon.Error);
                        return;
                    }
                    FileName = FileName.Replace("{Name}", ProjectName);
                    if (file.Attribute("External") != null)
                    {
                        if (file.Attribute("External").Value.ToLower() == "true")
                        {
                            if (File.Exists(Directory.GetCurrentDirectory() + "\\Templates\\" + FileName))
                                File.Copy(Directory.GetCurrentDirectory() + "\\Templates\\" + FileName,
                                    ProjectDirectory + "\\" + ProjectName + "\\" + FileName);
                            else
                                File.Copy(RuntimeData.tiDEUserDirectory + "\\Templates\\" + FileName,
                                    ProjectDirectory + "\\" + ProjectName + "\\" + FileName);
                        }
                        else
                        {
                            StreamWriter writer = new StreamWriter(File.Create(ProjectDirectory + "\\" + ProjectName + "\\" + FileName));
                            writer.Write(file.Value);
                            writer.Close();
                        }
                    }
                    else
                    {
                        StreamWriter writer = new StreamWriter(File.Create(ProjectDirectory + "\\" + ProjectName + "\\" + FileName));
                        writer.Write(file.Value);
                        writer.Close();
                    }
                    if (file.Attribute("Exclude") != null)
                    {
                        if (file.Attribute("Exclude").Value.ToLower() != "true")
                            Files.Add(FileName);
                    }
                    else
                        Files.Add(FileName);
                    if (file.Attribute("Open") != null)
                    {
                        try
                        {
                            if (bool.Parse(file.Attribute("Open").Value))
                            {
                                OpenFiles.Add(ProjectName + "\\" + FileName);
                            }
                        }
                        catch
                        {
                            MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK,MessageBoxIcon.Error);
                            return;
                        }
                    }
                    if (file.Attribute("Focus") != null)
                    {
                        try
                        {
                            if (bool.Parse(file.Attribute("Focus").Value))
                            {
                                FocusedFile = FileName;
                            }
                        }
                        catch
                        {
                            MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK,MessageBoxIcon.Error);
                            return;
                        }
                    }                    
                }
            }
            else
            {
                MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (templateElement.Element("SupportedModels") != null)
            {
                SupportedModels = new List<string>();
                foreach (XElement model in templateElement.Element("SupportedModels").Elements("SupportedModel"))
                {
                    SupportedModels.Add(model.Value);
                }
                if (SupportedModels.Count == 0 || templateElement.Element("SupportedModels").Element("SelectedModel") == null)
                {
                    MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                EmulatingModel = templateElement.Element("SupportedModels").Element("SelectedModel").Value;
            }
            else
            {
                MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            Dependencies = new List<string>();
            if (templateElement.Element("Dependencies") != null)
            {
                foreach (XElement dependency in templateElement.Element("Dependencies").Elements("Dependency"))
                {
                    Dependencies.Add(dependency.Value);
                }
            }

            Project project = new Project(ProjectName, ProjectType, Files, Packer, Dependencies,
                    SupportedModels, EmulatingModel, ProjectName);
            if (templateElement.Attribute("Icon") != null)
                project = new Project(ProjectName, ProjectType, Files, Packer, Dependencies,
                    SupportedModels, EmulatingModel, ProjectName, templateElement.Attribute("Icon").Value);
            if (projectDataType != null)
            {
                if (projectDataType.BaseType != typeof(Form) || 
                    !projectDataType.GetInterfaces().Contains(typeof(IProjectWizard))) // Must be an IProjectWizard and a Form
                {
                    MessageBox.Show("Project Template is invalid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                object instance = Activator.CreateInstance(projectDataType);
                (instance as Form).ShowDialog();
                project.Tag = (instance as IProjectWizard).ProjectData;
            }
            Solution.FocusedFile = FocusedFile;
            Solution.OpenFiles = OpenFiles;
            Solution.Projects.Add(project);
            DialogResult = System.Windows.Forms.DialogResult.OK;
            BinaryFormatter formatter = new BinaryFormatter();
            StreamWriter stream = new StreamWriter(ProjectDirectory + "\\" + ProjectName + ".tisln");
            formatter.Serialize(stream.BaseStream, Solution);
            stream.Close();
            stream = new StreamWriter(ProjectDirectory + "\\" + ProjectName + "\\" + ProjectName + ".tiproj");
            formatter.Serialize(stream.BaseStream, project);
            stream.Close();
            SolutionFile = ProjectDirectory + "\\" + ProjectName + ".tisln";
            this.Close();
        }

        public string SolutionFile;
    }
}
